home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / devel / tcl / tclx7_31.z / tclx7_31 / tcldev / tclX7.3a-p1 / src / tclXfilescan.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-25  |  20.0 KB  |  651 lines

  1. /*
  2.  * tclXfilescan.c --
  3.  *
  4.  * Tcl file scanning: regular expression matching on lines of a file.  
  5.  * Implements awk.
  6.  *-----------------------------------------------------------------------------
  7.  * Copyright 1991-1993 Karl Lehenbauer and Mark Diekhans.
  8.  *
  9.  * Permission to use, copy, modify, and distribute this software and its
  10.  * documentation for any purpose and without fee is hereby granted, provided
  11.  * that the above copyright notice appear in all copies.  Karl Lehenbauer and
  12.  * Mark Diekhans make no representations about the suitability of this
  13.  * software for any purpose.  It is provided "as is" without express or
  14.  * implied warranty.
  15.  *-----------------------------------------------------------------------------
  16.  * $Id: tclXfilescan.c,v 3.2 1994/01/25 01:07:01 markd Exp $
  17.  *-----------------------------------------------------------------------------
  18.  */
  19.  
  20. #include "tclExtdInt.h"
  21.  
  22. /*
  23.  * A scan context describes a collection of match patterns and commands,
  24.  * along with a match default command to apply to a file on a scan.
  25.  */
  26.  
  27. #define CONTEXT_A_CASE_INSENSITIVE_FLAG 2
  28. #define MATCH_CASE_INSENSITIVE_FLAG 4
  29.  
  30. typedef struct matchDef_t {
  31.     Tcl_regexp          regExpInfo;
  32.     char               *command;
  33.     struct matchDef_t  *nextMatchDefPtr;
  34.     short               matchflags;
  35. } matchDef_t;
  36.  
  37. typedef struct scanContext_t {
  38.     matchDef_t  *matchListHead;
  39.     matchDef_t  *matchListTail;
  40.     char        *defaultAction;
  41.     short        flags;
  42. } scanContext_t;
  43.  
  44. /*
  45.  * Prototypes of internal functions.
  46.  */
  47. static void
  48. CleanUpContext _ANSI_ARGS_((void_pt         scanTablePtr,
  49.                             scanContext_t  *contextPtr));
  50.  
  51. static int
  52. CreateScanContext _ANSI_ARGS_((Tcl_Interp  *interp,
  53.                                void_pt      scanTablePtr));
  54.  
  55. static int
  56. SelectScanContext _ANSI_ARGS_((Tcl_Interp  *interp,
  57.                                void_pt      scanTablePtr,
  58.                                char        *contextHandle));
  59.  
  60. static int
  61. Tcl_Delete_scancontextCmd _ANSI_ARGS_((Tcl_Interp  *interp,
  62.                                        void_pt      scanTablePtr,
  63.                                        char        *contextHandle));
  64.  
  65. static int
  66. SetMatchVar _ANSI_ARGS_((Tcl_Interp *interp,
  67.                          char       *fileLine,
  68.                          long        scanLineNum,
  69.                          FILE       *filePtr,
  70.                          FILE       *copyFilePtr));
  71.  
  72. static int
  73. SetSubMatchVar _ANSI_ARGS_((Tcl_Interp       *interp,
  74.                             char             *fileLine,
  75.                             Tcl_SubMatchInfo  subMatchInfo));
  76.  
  77. static void
  78. FileScanCleanUp _ANSI_ARGS_((ClientData  clientData,
  79.                              Tcl_Interp *interp));
  80.  
  81.  
  82. /*
  83.  *-----------------------------------------------------------------------------
  84.  * CleanUpContext --
  85.  *
  86.  *   Release all resources allocated to the specified scan context.  Doesn't
  87.  * free the table entry.
  88.  *-----------------------------------------------------------------------------
  89.  */
  90. static void
  91. CleanUpContext (scanTablePtr, contextPtr)
  92.     void_pt        scanTablePtr;
  93.     scanContext_t *contextPtr;
  94. {
  95.     matchDef_t  *matchPtr, *oldMatchPtr;
  96.  
  97.     for (matchPtr = contextPtr->matchListHead; matchPtr != NULL;) {
  98.         Tcl_RegExpClean (&matchPtr->regExpInfo);
  99.         if (matchPtr->command != NULL)
  100.             ckfree(matchPtr->command);
  101.         oldMatchPtr = matchPtr;
  102.         matchPtr = matchPtr->nextMatchDefPtr;
  103.         ckfree ((char *) oldMatchPtr);
  104.         }
  105.     if (contextPtr->defaultAction != NULL) {
  106.         ckfree(contextPtr->defaultAction);
  107.     }
  108.     ckfree (contextPtr);
  109. }
  110.  
  111. /*
  112.  *-----------------------------------------------------------------------------
  113.  * CreateScanContext --
  114.  *
  115.  *   Create a new scan context, implements the subcommand:
  116.  *         scancontext create
  117.  *-----------------------------------------------------------------------------
  118.  */
  119. static int
  120. CreateScanContext (interp, scanTablePtr)
  121.     Tcl_Interp  *interp;
  122.     void_pt      scanTablePtr;
  123. {
  124.     scanContext_t *contextPtr, **tableEntryPtr;
  125.     char           curName [16];
  126.  
  127.     contextPtr = (scanContext_t *) ckalloc (sizeof (scanContext_t));
  128.     contextPtr->flags = 0;
  129.     contextPtr->matchListHead = NULL;
  130.     contextPtr->matchListTail = NULL;
  131.     contextPtr->defaultAction = NULL;
  132.  
  133.     tableEntryPtr = (scanContext_t **) Tcl_HandleAlloc (scanTablePtr,
  134.                                                         curName);
  135.     *tableEntryPtr = contextPtr;
  136.  
  137.     Tcl_SetResult (interp, curName, TCL_STATIC);
  138.     return TCL_OK;
  139. }
  140.  
  141. /*
  142.  *-----------------------------------------------------------------------------
  143.  * DeleteScanContext --
  144.  *
  145.  *   Deletes the specified scan context, implements the subcommand:
  146.  *         scancontext delete contexthandle
  147.  *-----------------------------------------------------------------------------
  148.  */
  149. static int
  150. DeleteScanContext (interp, scanTablePtr, contextHandle)
  151.     Tcl_Interp  *interp;
  152.     void_pt      scanTablePtr;
  153.     char        *contextHandle;
  154. {
  155.     scanContext_t **tableEntryPtr;
  156.  
  157.     tableEntryPtr = (scanContext_t **) Tcl_HandleXlate (interp,
  158.                                                         scanTablePtr,
  159.                                                         contextHandle);
  160.     if (tableEntryPtr == NULL)
  161.         return TCL_ERROR;
  162.  
  163.     CleanUpContext (scanTablePtr, *tableEntryPtr);
  164.     Tcl_HandleFree (scanTablePtr, tableEntryPtr);
  165.  
  166.     return TCL_OK;
  167. }
  168.  
  169. /*
  170.  *-----------------------------------------------------------------------------
  171.  * Tcl_ScancontextCmd --
  172.  *
  173.  *   Implements the TCL scancontext Tcl command, which has the following forms:
  174.  *         scancontext create
  175.  *         scancontext delete
  176.  *-----------------------------------------------------------------------------
  177.  */
  178. static int
  179. Tcl_ScancontextCmd (clientData, interp, argc, argv)
  180.     char       *clientData;
  181.     Tcl_Interp *interp;
  182.     int         argc;
  183.     char      **argv;
  184. {
  185.     if (argc < 2) {
  186.         Tcl_AppendResult (interp, tclXWrongArgs, argv [0], " option",
  187.                           (char *) NULL);
  188.         return TCL_ERROR;
  189.     }
  190.     /*
  191.      * Create a new scan context.
  192.      */
  193.     if (STREQU (argv [1], "create")) {
  194.         if (argc != 2) {
  195.             Tcl_AppendResult (interp, tclXWrongArgs, argv [0], " create",
  196.                               (char *) NULL);
  197.             return TCL_ERROR;
  198.         }
  199.         return CreateScanContext (interp, (void_pt) clientData);
  200.     }
  201.     
  202.     /*
  203.      * Delete a scan context.
  204.      */
  205.     if (STREQU (argv [1], "delete")) {
  206.         if (argc != 3) {
  207.             Tcl_AppendResult (interp, tclXWrongArgs, argv [0],
  208.                               "delete contexthandle", (char *) NULL);
  209.             return TCL_ERROR;
  210.         }
  211.         return DeleteScanContext (interp, (void_pt) clientData, argv [2]);
  212.     }
  213.     
  214.     Tcl_AppendResult (interp, "invalid argument, expected one of: ",
  215.                       "create or delete", (char *) NULL);
  216.     return TCL_ERROR;
  217. }
  218.  
  219. /*
  220.  *-----------------------------------------------------------------------------
  221.  * Tcl_ScanmatchCmd --
  222.  *
  223.  *   Implements the TCL command:
  224.  *         scanmatch ?-nocase? contexthandle ?regexp? command
  225.  *
  226.  *   This uses both Boyer_Moore and regular expressions matching.
  227.  *-----------------------------------------------------------------------------
  228.  */
  229. static int
  230. Tcl_ScanmatchCmd (clientData, interp, argc, argv)
  231.     char       *clientData;
  232.     Tcl_Interp *interp;
  233.     int         argc;
  234.     char      **argv;
  235. {
  236.     scanContext_t  *contextPtr, **tableEntryPtr;
  237.     char           *result;
  238.     matchDef_t     *newmatch;
  239.     int             compFlags = REXP_BOTH_ALGORITHMS;
  240.     int             firstArg = 1;
  241.  
  242.     if (argc < 3)
  243.         goto argError;
  244.     if (STREQU (argv[1], "-nocase")) {
  245.         compFlags |= REXP_NO_CASE;
  246.         firstArg = 2;
  247.     }
  248.       
  249.     /*
  250.      * If firstArg == 2 (-nocase), the both a regular expression and a command
  251.      * string must be specified, otherwise the regular expression is optional.
  252.      */
  253.     if (((firstArg == 2) && (argc != 5)) || ((firstArg == 1) && (argc > 4)))
  254.         goto argError;
  255.  
  256.     tableEntryPtr = (scanContext_t **)
  257.         Tcl_HandleXlate (interp,
  258.                          (void_pt) clientData, 
  259.                          argv [firstArg]);
  260.     if (tableEntryPtr == NULL)
  261.         return TCL_ERROR;
  262.     contextPtr = *tableEntryPtr;
  263.  
  264.     /*
  265.      * Handle the default case (no regular expression).
  266.      */
  267.     if (argc == 3) {
  268.         if (contextPtr->defaultAction) {
  269.             Tcl_AppendResult (interp, argv [0], ": default match already ",
  270.                               "specified in this scan context", (char *) NULL);
  271.             return TCL_ERROR;
  272.         }
  273.         contextPtr->defaultAction = ckstrdup (argv [2]);
  274.  
  275.         return TCL_OK;
  276.     }
  277.  
  278.     /*
  279.      * Add a regular expression to the context.
  280.      */
  281.  
  282.     newmatch = (matchDef_t *) ckalloc(sizeof (matchDef_t));
  283.     newmatch->matchflags = 0;
  284.  
  285.     if (compFlags & REXP_NO_CASE) {
  286.         newmatch->matchflags |= MATCH_CASE_INSENSITIVE_FLAG;
  287.         contextPtr->flags |= CONTEXT_A_CASE_INSENSITIVE_FLAG;
  288.     }
  289.  
  290.     if (Tcl_RegExpCompile (interp, &newmatch->regExpInfo, argv [firstArg + 1], 
  291.                            compFlags) != TCL_OK) {
  292.         ckfree ((char *) newmatch);
  293.         return (TCL_ERROR);
  294.     }
  295.  
  296.     newmatch->command = ckstrdup (argv [firstArg + 2]);
  297.  
  298.     /*
  299.      * Link in the new match.
  300.      */
  301.     newmatch->nextMatchDefPtr = NULL;
  302.     if (contextPtr->matchListHead == NULL)
  303.         contextPtr->matchListHead = newmatch;
  304.     else
  305.         contextPtr->matchListTail->nextMatchDefPtr = newmatch;
  306.     contextPtr->matchListTail = newmatch;
  307.  
  308.     return TCL_OK;
  309.  
  310. argError:
  311.     Tcl_AppendResult (interp, tclXWrongArgs, argv [0],
  312.                       " ?-nocase? contexthandle ?regexp? command",
  313.                       (char *) NULL);
  314.     return TCL_ERROR;
  315. }
  316.  
  317. /*
  318.  *-----------------------------------------------------------------------------
  319.  * SetMatchVar --
  320.  *
  321.  *   Sets the TCL array variable matchInfo to contain information 
  322.  * about the line that is matched.
  323.  *-----------------------------------------------------------------------------
  324.  */
  325. static int
  326. SetMatchVar (interp, fileLine, scanLineNum, filePtr, copyFilePtr)
  327.     Tcl_Interp *interp;
  328.     char       *fileLine;
  329.     long        scanLineNum;
  330.     FILE       *filePtr;
  331.     FILE       *copyFilePtr;
  332. {
  333.     static char *MATCHINFO = "matchInfo";
  334.     static char *FILEFMT   = "file%d";
  335.     int          matchOffset;
  336.     char         buf [32];
  337.  
  338.     Tcl_UnsetVar (interp, MATCHINFO, 0);
  339.  
  340.     matchOffset = ftell (filePtr) - (strlen (fileLine) + 1);
  341.  
  342.     if (Tcl_SetVar2 (interp, MATCHINFO, "line", fileLine, 
  343.                      TCL_LEAVE_ERR_MSG) == NULL)
  344.         return TCL_ERROR;
  345.  
  346.     sprintf (buf, "%ld", matchOffset);
  347.     if (Tcl_SetVar2 (interp, MATCHINFO, "offset", buf,
  348.                      TCL_LEAVE_ERR_MSG) == NULL)
  349.         return TCL_ERROR;
  350.  
  351.     sprintf (buf, "%ld", scanLineNum);
  352.     if (Tcl_SetVar2 (interp, MATCHINFO, "linenum", buf,
  353.                      TCL_LEAVE_ERR_MSG) == NULL)
  354.         return TCL_ERROR;
  355.  
  356.     sprintf (buf, FILEFMT, fileno (filePtr));
  357.     if (Tcl_SetVar2 (interp, MATCHINFO, "handle", buf, 
  358.                      TCL_LEAVE_ERR_MSG) == NULL)
  359.         return TCL_ERROR;
  360.     if (copyFilePtr != NULL) {
  361.         sprintf (buf, FILEFMT, fileno (copyFilePtr));
  362.         if (Tcl_SetVar2 (interp, MATCHINFO, "copyHandle", buf, 
  363.                          TCL_LEAVE_ERR_MSG) == NULL)
  364.             return TCL_ERROR;
  365.     }
  366.     return TCL_OK;
  367. }
  368.  
  369. /*
  370.  *-----------------------------------------------------------------------------
  371.  * SetSubMatchVar --
  372.  *
  373.  *   Sets the TCL array variable matchInfo entries to describe the matching
  374.  * subexpressions.
  375.  *-----------------------------------------------------------------------------
  376.  */
  377. static int
  378. SetSubMatchVar (interp, fileLine, subMatchInfo)
  379.     Tcl_Interp       *interp;
  380.     char             *fileLine;
  381.     Tcl_SubMatchInfo  subMatchInfo;
  382. {
  383.     int  idx, start, end;
  384.     char key [32], buf [32], *varPtr, holdChar;
  385.     
  386.     for (idx = 0; subMatchInfo [idx].start >= 0; idx++) {
  387.         start = subMatchInfo [idx].start;
  388.         end = subMatchInfo [idx].end;
  389.  
  390.         sprintf (key, "subindex%d", idx);
  391.         sprintf (buf, "%d %d", start, end);
  392.         varPtr = Tcl_SetVar2 (interp, "matchInfo", key, buf,
  393.                               TCL_LEAVE_ERR_MSG);
  394.         if (varPtr == NULL)
  395.             return TCL_ERROR;
  396.  
  397.         sprintf (key, "submatch%d", idx);
  398.         holdChar = fileLine [end + 1];
  399.         fileLine [end + 1] = '\0';
  400.         varPtr = Tcl_SetVar2 (interp, "matchInfo", key,
  401.                               fileLine + start,
  402.                               TCL_LEAVE_ERR_MSG);
  403.         fileLine [end + 1] = holdChar;
  404.         if (varPtr == NULL)
  405.             return TCL_ERROR;
  406.     }
  407.     return TCL_OK;
  408. }
  409.  
  410. /*
  411.  *-----------------------------------------------------------------------------
  412.  * Tcl_ScanfileCmd --
  413.  *
  414.  *   Implements the TCL command:
  415.  *        scanfile contexthandle filehandle
  416.  *-----------------------------------------------------------------------------
  417.  */
  418. static int
  419. Tcl_ScanfileCmd (clientData, interp, argc, argv)
  420.     char       *clientData;
  421.     Tcl_Interp *interp;
  422.     int         argc;
  423.     char      **argv;
  424. {
  425.     scanContext_t    *contextPtr, **tableEntryPtr;
  426.     Tcl_DString       dynBuf, lowerDynBuf;
  427.     FILE             *filePtr;
  428.     matchDef_t       *matchPtr;
  429.     int               contextHandleIndex, fileHandleIndex;
  430.     int               result, matchedAtLeastOne, status, storedThisLine;
  431.     long              scanLineNum = 0;
  432.     char             *fileHandle;
  433.     Tcl_SubMatchInfo  subMatchInfo;
  434.     FILE             *copytoFilePtr;
  435.  
  436.     if ((argc != 3) && (argc != 5)) goto argError;
  437.  
  438.     if (argc == 3) {
  439.     contextHandleIndex = 1;
  440.     fileHandleIndex = 2;
  441.     copytoFilePtr = NULL;
  442.     } else {
  443.     if (!STREQU (argv[1], "-copyfile")) goto argError;
  444.     contextHandleIndex = 3;
  445.     fileHandleIndex = 4;
  446.  
  447.         if (Tcl_GetOpenFile (interp, argv [2],
  448.                  TRUE,  /* Write access  */
  449.                  TRUE,   /* Check access */
  450.                  ©toFilePtr) != TCL_OK) {
  451.         return TCL_ERROR;
  452.     }
  453.     }
  454.  
  455.     tableEntryPtr = (scanContext_t **)
  456.         Tcl_HandleXlate (interp,
  457.                          (void_pt) clientData, 
  458.                          argv [contextHandleIndex]);
  459.     if (tableEntryPtr == NULL)
  460.         return TCL_ERROR;
  461.     contextPtr = *tableEntryPtr;
  462.  
  463.     if (Tcl_GetOpenFile (interp, argv [fileHandleIndex],
  464.                          FALSE,  /* Read access  */
  465.                          TRUE,   /* Check access */
  466.                          &filePtr) != TCL_OK)
  467.             return TCL_ERROR;
  468.  
  469.     if (contextPtr->matchListHead == NULL) {
  470.         Tcl_AppendResult (interp, "no patterns in current scan context",
  471.                           (char *) NULL);
  472.         return TCL_ERROR;
  473.     }
  474.  
  475.     Tcl_DStringInit (&dynBuf);
  476.     Tcl_DStringInit (&lowerDynBuf);
  477.  
  478.     result = TCL_OK;
  479.     while (TRUE) {
  480.         Tcl_DStringFree (&dynBuf);
  481.         status = Tcl_DStringGets (filePtr, &dynBuf) ;
  482.  
  483.         if (status == TCL_ERROR) {
  484.             interp->result = Tcl_PosixError (interp);
  485.             result = TCL_ERROR;
  486.             goto scanExit;
  487.         }
  488.         if (status == TCL_BREAK)
  489.             goto scanExit;  /* EOF */
  490.  
  491.         scanLineNum++;
  492.         storedThisLine = FALSE;
  493.         matchedAtLeastOne = FALSE;
  494.  
  495.         if (contextPtr->flags & CONTEXT_A_CASE_INSENSITIVE_FLAG) {
  496.             Tcl_DStringFree (&lowerDynBuf);
  497.             Tcl_DStringAppend (&lowerDynBuf, dynBuf.string, -1);
  498.             Tcl_DownShift (lowerDynBuf.string, lowerDynBuf.string);
  499.         }
  500.  
  501.         for (matchPtr = contextPtr->matchListHead; matchPtr != NULL; 
  502.                  matchPtr = matchPtr->nextMatchDefPtr) {
  503.  
  504.             if (!Tcl_RegExpExecute (interp,
  505.                                     &matchPtr->regExpInfo,
  506.                                     dynBuf.string,
  507.                                     lowerDynBuf.string,
  508.                                     subMatchInfo))
  509.                 continue;  /* Try next match pattern */
  510.  
  511.             matchedAtLeastOne = TRUE;
  512.             if (!storedThisLine) {
  513.                 result = SetMatchVar (interp,
  514.                                       dynBuf.string,
  515.                                       scanLineNum,
  516.                                       filePtr,
  517.                                       copytoFilePtr);
  518.                 if (result != TCL_OK)
  519.                     goto scanExit;
  520.                 storedThisLine = TRUE;
  521.             }
  522.             result = SetSubMatchVar (interp, dynBuf.string, subMatchInfo);
  523.             if (result != TCL_OK)
  524.                 goto scanExit;
  525.  
  526.             result = Tcl_Eval(interp, matchPtr->command);
  527.             if (result == TCL_ERROR) {
  528.                 Tcl_AddErrorInfo (interp, 
  529.                     "\n    while executing a match command");
  530.                 goto scanExit;
  531.             }
  532.             if (result == TCL_CONTINUE) {
  533.                 /* 
  534.                  * Don't process any more matches for this line.
  535.                  */
  536.                 goto matchLineExit;
  537.             }
  538.             if (result == TCL_BREAK) {
  539.                 /*
  540.                  * Terminate scan.
  541.                  */
  542.                 result = TCL_OK;
  543.                 goto scanExit;
  544.             }
  545.         }
  546.  
  547.         matchLineExit:
  548.         /*
  549.          * Process default action if required.
  550.          */
  551.         if ((contextPtr->defaultAction != NULL) && (!matchedAtLeastOne)) {
  552.             result = SetMatchVar (interp,
  553.                                   dynBuf.string,
  554.                                   scanLineNum,
  555.                                   filePtr,
  556.                                   copytoFilePtr);
  557.             if (result != TCL_OK)
  558.                 goto scanExit;
  559.  
  560.             result = Tcl_Eval (interp, contextPtr->defaultAction);
  561.             if (result == TCL_ERROR)
  562.                 Tcl_AddErrorInfo (interp, 
  563.                     "\n    while executing a match default command");
  564.             if (result == TCL_BREAK)
  565.                 goto scanExit;
  566.         }
  567.  
  568.     if ((copytoFilePtr != NULL) && (!matchedAtLeastOne)) {
  569.         if (fputs (dynBuf.string, copytoFilePtr) == EOF) {
  570.         interp->result = Tcl_PosixError (interp);
  571.         return TCL_ERROR;
  572.         }
  573.         if (fputs ("\n", copytoFilePtr) == EOF) {
  574.         interp->result = Tcl_PosixError (interp);
  575.         return TCL_ERROR;
  576.         }
  577.     }
  578.     }
  579. scanExit:
  580.     Tcl_DStringFree (&dynBuf);
  581.     Tcl_DStringFree (&lowerDynBuf);
  582.     if (result == TCL_ERROR)
  583.         return TCL_ERROR;
  584.     return TCL_OK;
  585.  
  586. argError:
  587.     Tcl_AppendResult (interp, tclXWrongArgs, argv [0], 
  588.               " ?-copyfile filehandle? contexthandle filehandle", 
  589.               (char *) NULL);
  590.     return TCL_ERROR;
  591. }
  592.  
  593. /*
  594.  *-----------------------------------------------------------------------------
  595.  * FileScanCleanUp --
  596.  *
  597.  *    Called when the interpreter is deleted to cleanup all filescan
  598.  * resources
  599.  *-----------------------------------------------------------------------------
  600.  */
  601. static void
  602. FileScanCleanUp (clientData, interp)
  603.     ClientData  clientData;
  604.     Tcl_Interp *interp;
  605. {
  606.     scanContext_t **tableEntryPtr;
  607.     int             walkKey;
  608.     
  609.     walkKey = -1;
  610.     while (TRUE) {
  611.         tableEntryPtr =
  612.             (scanContext_t **) Tcl_HandleWalk ((void_pt) clientData, 
  613.                                                &walkKey);
  614.         if (tableEntryPtr == NULL)
  615.             break;
  616.         CleanUpContext ((void_pt) clientData, *tableEntryPtr);
  617.     }
  618.     Tcl_HandleTblRelease ((void_pt) clientData);
  619. }
  620.  
  621. /*
  622.  *-----------------------------------------------------------------------------
  623.  *  Tcl_InitFilescan --
  624.  *
  625.  *    Initialize the TCL file scanning facility..
  626.  *-----------------------------------------------------------------------------
  627.  */
  628. void
  629. Tcl_InitFilescan (interp)
  630.     Tcl_Interp *interp;
  631. {
  632.     void_pt  scanTablePtr;
  633.  
  634.     scanTablePtr = Tcl_HandleTblInit ("context",
  635.                                       sizeof (scanContext_t *),
  636.                                       10);
  637.  
  638.     Tcl_CallWhenDeleted (interp, FileScanCleanUp, (ClientData) scanTablePtr);
  639.  
  640.     /*
  641.      * Initialize the commands.
  642.      */
  643.     Tcl_CreateCommand (interp, "scanfile", Tcl_ScanfileCmd, 
  644.                        (ClientData) scanTablePtr, (void (*)()) NULL);
  645.     Tcl_CreateCommand (interp, "scanmatch", Tcl_ScanmatchCmd, 
  646.                        (ClientData) scanTablePtr, (void (*)()) NULL);
  647.     Tcl_CreateCommand (interp, "scancontext", Tcl_ScancontextCmd,
  648.                        (ClientData) scanTablePtr, (void (*)()) NULL);
  649. }
  650.  
  651.